home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-24 | 54.4 KB | 2,580 lines |
- Newsgroups: comp.sources.misc
- From: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Subject: v26i060: shadow - Shadow Password Suite, Part07/11
- Message-ID: <1991Nov24.185134.20472@sparky.imd.sterling.com>
- X-Md4-Signature: 44ff75e892205797906d354d2e99bf09
- Date: Sun, 24 Nov 1991 18:51:34 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II)
- Posting-number: Volume 26, Issue 60
- Archive-name: shadow/part07
- Environment: UNIX
- Supersedes: shadow-2: Volume 06, Issue 22-24
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: copydir.c getdef.c grdbm.c groupmod.c mkpasswd.c port.c
- # shadow.c
- # Wrapped by kent@sparky on Sun Nov 24 11:03:43 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 7 (of 11)."'
- if test -f 'copydir.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'copydir.c'\"
- else
- echo shar: Extracting \"'copydir.c'\" \(7131 characters\)
- sed "s/^X//" >'copydir.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, John F. Haugh II
- X * An unpublished work.
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "config.h"
- X#ifdef DIR_XENIX
- X#include <sys/ndir.h>
- X#define DIRECT direct
- X#endif
- X#ifdef DIR_BSD
- X#include <ndir.h>
- X#define DIRECT direct
- X#endif
- X#ifdef DIR_SYSV
- X#include <dirent.h>
- X#define DIRECT dirent
- X#endif
- X#include <fcntl.h>
- X#include <stdio.h>
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)copydir.c 3.1 10:09:26 6/13/91";
- X#endif
- X
- X#ifndef S_ISDIR
- X#define S_ISDIR(x) (((x)&S_IFMT)==S_IFDIR)
- X#endif
- X#ifndef S_ISREG
- X#define S_ISREG(x) (((x)&S_IFMT)==S_IFREG)
- X#endif
- X
- Xstatic char *src_orig;
- Xstatic char *dst_orig;
- X
- Xstruct link_name {
- X int ln_dev;
- X int ln_ino;
- X int ln_count;
- X char *ln_name;
- X struct link_name *ln_next;
- X};
- Xstatic struct link_name *links;
- X
- X/*
- X * remove_link - delete a link from the link list
- X */
- X
- Xvoid
- Xremove_link (link)
- Xstruct link_name *link;
- X{
- X struct link_name *lp;
- X
- X if (links == link) {
- X links = link->ln_next;
- X free (link->ln_name);
- X free (link);
- X return;
- X }
- X for (lp = links;lp;lp = lp->ln_next)
- X if (lp->ln_next == link)
- X break;
- X
- X if (! lp)
- X return;
- X
- X lp->ln_next = lp->ln_next->ln_next;
- X free (link->ln_name);
- X free (link);
- X}
- X
- X/*
- X * check_link - see if a file is really a link
- X */
- X
- Xstruct link_name *
- Xcheck_link (name, sb)
- Xchar *name;
- Xstruct stat *sb;
- X{
- X struct link_name *lp;
- X int src_len;
- X int dst_len;
- X int name_len;
- X char *malloc ();
- X
- X for (lp = links;lp;lp = lp->ln_next)
- X if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
- X return lp;
- X
- X if (sb->st_nlink == 1)
- X return 0;
- X
- X lp = (struct link_name *) malloc (sizeof *lp);
- X src_len = strlen (src_orig);
- X dst_len = strlen (dst_orig);
- X name_len = strlen (name);
- X lp->ln_dev = sb->st_dev;
- X lp->ln_ino = sb->st_ino;
- X lp->ln_count = sb->st_nlink;
- X lp->ln_name = malloc (name_len - src_len + dst_len + 1);
- X sprintf (lp->ln_name, "%s%s", dst_orig, name + src_len);
- X lp->ln_next = links;
- X links = lp;
- X
- X return 0;
- X}
- X
- X/*
- X * copy_tree - copy files in a directory tree
- X *
- X * copy_tree() walks a directory tree and copies ordinary files
- X * as it goes.
- X */
- X
- Xint
- Xcopy_tree (src_root, dst_root, uid, gid)
- Xchar *src_root;
- Xchar *dst_root;
- Xint uid;
- Xint gid;
- X{
- X char src_name[BUFSIZ];
- X char dst_name[BUFSIZ];
- X char buf[BUFSIZ];
- X int ifd;
- X int ofd;
- X int err = 0;
- X int cnt;
- X int set_orig = 0;
- X struct DIRECT *ent;
- X struct stat sb;
- X struct link_name *lp;
- X DIR *dir;
- X
- X /*
- X * Make certain both directories exist. This routine is called
- X * after the home directory is created, or recursively after the
- X * target is created. It assumes the target directory exists.
- X */
- X
- X if (access (src_root, 0) != 0 || access (dst_root, 0) != 0)
- X return -1;
- X
- X /*
- X * Open the source directory and read each entry. Every file
- X * entry in the directory is copied with the UID and GID set
- X * to the provided values. As an added security feature only
- X * regular files (and directories ...) are copied, and no file
- X * is made set-ID.
- X */
- X
- X if (! (dir = opendir (src_root)))
- X return -1;
- X
- X if (src_orig == 0) {
- X src_orig = src_root;
- X dst_orig = dst_root;
- X set_orig++;
- X }
- X while (ent = readdir (dir)) {
- X
- X /*
- X * Skip the "." and ".." entries
- X */
- X
- X if (strcmp (ent->d_name, ".") == 0 ||
- X strcmp (ent->d_name, "..") == 0)
- X continue;
- X
- X /*
- X * Make the filename for both the source and the
- X * destination files.
- X */
- X
- X if (strlen (src_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
- X err++;
- X break;
- X }
- X sprintf (src_name, "%s/%s", src_root, ent->d_name);
- X
- X if (strlen (dst_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
- X err++;
- X break;
- X }
- X sprintf (dst_name, "%s/%s", dst_root, ent->d_name);
- X
- X if (stat (src_name, &sb) == -1)
- X continue;
- X
- X if (S_ISDIR (sb.st_mode)) {
- X
- X /*
- X * Create a new target directory, make it owned by
- X * the user and then recursively copy that directory.
- X */
- X
- X mkdir (dst_name, sb.st_mode & 0777);
- X chown (dst_name, uid == -1 ? sb.st_uid:uid,
- X gid == -1 ? sb.st_gid:gid);
- X
- X if (copy_tree (src_name, dst_name, uid, gid)) {
- X err++;
- X break;
- X }
- X continue;
- X }
- X
- X /*
- X * See if this is a previously copied link
- X */
- X
- X if (lp = check_link (src_name, &sb)) {
- X if (link (lp->ln_name, dst_name)) {
- X err++;
- X break;
- X }
- X if (unlink (src_name)) {
- X err++;
- X break;
- X }
- X if (--lp->ln_count <= 0)
- X remove_link (lp);
- X
- X continue;
- X }
- X
- X /*
- X * Deal with FIFOs and special files. The user really
- X * shouldn't have any of these, but it seems like it
- X * would be nice to copy everything ...
- X */
- X
- X if (! S_ISREG (sb.st_mode)) {
- X if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) ||
- X chown (dst_name, uid == -1 ? sb.st_uid:uid,
- X gid == -1 ? sb.st_gid:gid) ||
- X chmod (dst_name, sb.st_mode & 07777)) {
- X err++;
- X break;
- X }
- X continue;
- X }
- X
- X /*
- X * Create the new file and copy the contents. The new
- X * file will be owned by the provided UID and GID values.
- X */
- X
- X if ((ifd = open (src_name, O_RDONLY)) < 0) {
- X err++;
- X break;
- X }
- X if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 ||
- X chown (dst_name, uid == -1 ? sb.st_uid:uid,
- X gid == -1 ? sb.st_gid:gid) ||
- X chmod (dst_name, sb.st_mode & 07777)) {
- X close (ifd);
- X err++;
- X break;
- X }
- X while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
- X if (write (ofd, buf, cnt) != cnt) {
- X cnt = -1;
- X break;
- X }
- X }
- X close (ifd);
- X close (ofd);
- X
- X if (cnt == -1) {
- X err++;
- X break;
- X }
- X }
- X closedir (dir);
- X
- X if (set_orig) {
- X src_orig = 0;
- X dst_orig = 0;
- X }
- X return err ? -1:0;
- X}
- X
- X/*
- X * remove_tree - remove files in a directory tree
- X *
- X * remove_tree() walks a directory tree and deletes all the files
- X * and directories.
- X */
- X
- Xint
- Xremove_tree (root)
- Xchar *root;
- X{
- X char new_name[BUFSIZ];
- X int err = 0;
- X struct DIRECT *ent;
- X struct stat sb;
- X DIR *dir;
- X
- X /*
- X * Make certain the directory exists.
- X */
- X
- X if (access (root, 0) != 0)
- X return -1;
- X
- X /*
- X * Open the source directory and read each entry. Every file
- X * entry in the directory is copied with the UID and GID set
- X * to the provided values. As an added security feature only
- X * regular files (and directories ...) are copied, and no file
- X * is made set-ID.
- X */
- X
- X dir = opendir (root);
- X
- X while (ent = readdir (dir)) {
- X
- X /*
- X * Skip the "." and ".." entries
- X */
- X
- X if (strcmp (ent->d_name, ".") == 0 ||
- X strcmp (ent->d_name, "..") == 0)
- X continue;
- X
- X /*
- X * Make the filename for the current entry.
- X */
- X
- X if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ) {
- X err++;
- X break;
- X }
- X sprintf (new_name, "%s/%s", root, ent->d_name);
- X if (stat (new_name, &sb) == -1)
- X continue;
- X
- X if (S_ISDIR (sb.st_mode)) {
- X
- X /*
- X * Recursively delete this directory.
- X */
- X
- X if (remove_tree (new_name)) {
- X err++;
- X break;
- X }
- X if (rmdir (new_name)) {
- X err++;
- X break;
- X }
- X continue;
- X }
- X unlink (new_name);
- X }
- X closedir (dir);
- X
- X return err ? -1:0;
- X}
- END_OF_FILE
- if test 7131 -ne `wc -c <'copydir.c'`; then
- echo shar: \"'copydir.c'\" unpacked with wrong size!
- fi
- # end of 'copydir.c'
- fi
- if test -f 'getdef.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'getdef.c'\"
- else
- echo shar: Extracting \"'getdef.c'\" \(6898 characters\)
- sed "s/^X//" >'getdef.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, John F. Haugh II and Chip Rosenthal
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)getdef.c 3.2 20:54:06 9/18/91";
- X#endif
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#ifndef BSD
- X# include <string.h>
- X#else
- X# include <strings.h>
- X#endif
- X#include "config.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X
- X#ifndef LOG_WARN
- X#define LOG_WARN LOG_WARNING
- X#endif
- X#endif
- X
- X/*
- X * A configuration item definition.
- X */
- X
- Xstruct itemdef {
- X char *name; /* name of the item */
- X char *value; /* value given, or NULL if no value */
- X};
- X
- X/*
- X * This list *must* be sorted by the "name" member.
- X */
- X
- X#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
- Xstruct itemdef def_table[] = {
- X { "CONSOLE", NULL },
- X { "DIALUPS_CHECK_ENAB", NULL },
- X { "ENV_HZ", NULL },
- X { "ENV_PATH" , NULL },
- X { "ENV_SUPATH", NULL },
- X { "ENV_TZ", NULL },
- X { "ERASECHAR", NULL },
- X { "FAILLOG_ENAB", NULL },
- X { "FTMP_FILE", NULL },
- X { "HUSHLOGIN_FILE", NULL },
- X { "ISSUE_FILE_ENAB", NULL },
- X { "KILLCHAR", NULL },
- X { "LASTLOG_ENAB", NULL },
- X { "LOG_UNKFAIL_ENAB", NULL },
- X { "MAIL_CHECK_ENAB", NULL },
- X { "MAIL_DIR", NULL },
- X { "MOTD_FILE", NULL },
- X { "NOLOGINS_FILE", NULL },
- X { "NOLOGIN_STR", NULL },
- X { "OBSCURE_CHECKS_ENAB", NULL },
- X { "PASS_MAX_DAYS", NULL },
- X { "PASS_MIN_DAYS", NULL },
- X { "PASS_MIN_LEN", NULL },
- X { "PASS_WARN_AGE", NULL },
- X { "PORTTIME_CHECKS_ENAB", NULL },
- X { "QUOTAS_ENAB", NULL },
- X { "SULOG_FILE", NULL },
- X { "SYSLOG_SU_ENAB", NULL },
- X { "TTYPERM", NULL },
- X { "TTYTYPE_FILE", NULL },
- X { "ULIMIT", NULL },
- X { "UMASK", NULL },
- X};
- X
- Xstatic char def_fname[] = LOGINDEFS; /* login config defs file */
- Xstatic int def_loaded = 0; /* are defs already loaded? */
- X
- Xextern long strtol();
- X
- Xstatic struct itemdef *def_find();
- Xstatic void def_load();
- X
- X
- X/*
- X * getdef_str - get string value from table of definitions.
- X *
- X * Return point to static data for specified item, or NULL if item is not
- X * defined. First time invoked, will load definitions from the file.
- X */
- X
- Xchar *
- Xgetdef_str(item)
- Xchar *item;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X return ((d = def_find(item)) == NULL ? (char *)NULL : d->value);
- X}
- X
- X
- X/*
- X * getdef_bool - get boolean value from table of definitions.
- X *
- X * Return TRUE if specified item is defined as "yes", else FALSE.
- X */
- X
- Xint
- Xgetdef_bool(item)
- Xchar *item;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return 0;
- X
- X return (strcmp(d->value, "yes") == 0);
- X}
- X
- X
- X/*
- X * getdef_num - get numerical value from table of definitions
- X *
- X * Returns numeric value of specified item, else the "dflt" value if
- X * the item is not defined. Octal (leading "0") and hex (leading "0x")
- X * values are handled.
- X */
- X
- Xint
- Xgetdef_num(item, dflt)
- Xchar *item;
- Xint dflt;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return dflt;
- X
- X return (int) strtol(d->value, (char **)NULL, 0);
- X}
- X
- X
- X/*
- X * getdef_long - get long integer value from table of definitions
- X *
- X * Returns numeric value of specified item, else the "dflt" value if
- X * the item is not defined. Octal (leading "0") and hex (leading "0x")
- X * values are handled.
- X */
- X
- Xlong
- Xgetdef_long(item, dflt)
- Xchar *item;
- Xlong dflt;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return dflt;
- X
- X return strtol(d->value, (char **)NULL, 0);
- X}
- X
- X/*
- X * def_find - locate named item in table
- X *
- X * Search through a sorted table of configurable items to locate the
- X * specified configuration option.
- X */
- X
- Xstatic struct itemdef *
- Xdef_find(name)
- Xchar *name;
- X{
- X int min, max, curr, n;
- X
- X /*
- X * Invariant - desired item in range [min:max].
- X */
- X
- X min = 0;
- X max = NUMDEFS-1;
- X
- X /*
- X * Binary search into the table. Relies on the items being
- X * sorted by name.
- X */
- X
- X while (min <= max) {
- X curr = (min+max)/2;
- X
- X if (! (n = strcmp(def_table[curr].name, name)))
- X return &def_table[curr];
- X
- X if (n < 0)
- X min = curr+1;
- X else
- X max = curr-1;
- X }
- X
- X /*
- X * Item was never found.
- X */
- X
- X fprintf(stderr, "configuration error - unknown item '%s' (notify administrator)\r\n", name);
- X#ifdef USE_SYSLOG
- X syslog(LOG_CRIT, "unknown configuration item `%s'", name);
- X#endif
- X return (struct itemdef *) NULL;
- X}
- X
- X/*
- X * def_load - load configuration table
- X *
- X * Loads the user-configured options from the default configuration file
- X */
- X
- Xstatic void
- Xdef_load()
- X{
- X int i;
- X FILE *fp;
- X struct itemdef *d;
- X char buf[BUFSIZ], *name, *value, *s;
- X
- X#ifdef CKDEFS
- X
- X /*
- X * Set this flag early so the errors will be reported only
- X * during testing.
- X */
- X
- X ++def_loaded;
- X#endif
- X
- X /*
- X * Open the configuration definitions file.
- X */
- X
- X if ((fp = fopen(def_fname, "r")) == NULL) {
- X#ifdef USE_SYSLOG
- X extern int errno;
- X extern char *sys_errlist[];
- X
- X syslog(LOG_CRIT, "cannot open login definitions %s [%s]",
- X def_fname, sys_errlist[errno]);
- X#endif
- X return;
- X }
- X
- X /*
- X * Go through all of the lines in the file.
- X */
- X
- X while (fgets(buf, sizeof(buf), fp) != NULL) {
- X
- X /*
- X * Trim trailing whitespace.
- X */
- X
- X for (i = strlen(buf)-1 ; i >= 0 ; --i) {
- X if (!isspace(buf[i]))
- X break;
- X }
- X buf[++i] = '\0';
- X
- X /*
- X * Break the line into two fields.
- X */
- X
- X name = buf + strspn(buf, " \t"); /* first nonwhite */
- X if (*name == '\0' || *name == '#')
- X continue; /* comment or empty */
- X
- X s = name + strcspn(name, " \t"); /* end of field */
- X if (*s == '\0')
- X continue; /* only 1 field?? */
- X
- X *s++ = '\0';
- X value = s + strspn(s, " \t"); /* next nonwhite */
- X
- X /*
- X * Locate the slot to save the value. If this parameter
- X * is unknown then "def_find" will print an err message.
- X */
- X
- X if ((d = def_find(name)) == NULL)
- X continue;
- X
- X /*
- X * Save off the value.
- X */
- X
- X if ((d->value = strdup(value)) == NULL) {
- X if (! def_loaded)
- X break;
- X
- X fputs("Could not allocate space for config info.\r\n", stderr);
- X#ifndef CKDEFS
- X#ifdef USE_SYSLOG
- X syslog(LOG_ERR, "could not allocate space for config info");
- X#endif
- X#endif
- X break;
- X }
- X }
- X (void) fclose(fp);
- X
- X /*
- X * Set the initialized flag.
- X */
- X
- X ++def_loaded;
- X}
- X
- X#ifdef CKDEFS
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X int i;
- X char *cp;
- X struct itemdef *d;
- X
- X def_load ();
- X
- X for (i = 0 ; i < NUMDEFS ; ++i) {
- X if ((d = def_find(def_table[i].name)) == NULL)
- X printf("error - lookup '%s' failed\n", def_table[i].name);
- X else
- X printf("%4d %-24s %s\n", i+1, d->name, d->value);
- X }
- X for (i = 1;i < argc;i++) {
- X if (cp = getdef_str (argv[1]))
- X printf ("%s `%s'\n", argv[1], cp);
- X else
- X printf ("%s not found\n", argv[1]);
- X }
- X exit(0);
- X}
- X#endif
- END_OF_FILE
- if test 6898 -ne `wc -c <'getdef.c'`; then
- echo shar: \"'getdef.c'\" unpacked with wrong size!
- fi
- # end of 'getdef.c'
- fi
- if test -f 'grdbm.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'grdbm.c'\"
- else
- echo shar: Extracting \"'grdbm.c'\" \(3618 characters\)
- sed "s/^X//" >'grdbm.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Use, duplication, and disclosure prohibited without
- X * the express written permission of the author.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)grdbm.c 3.3 08:44:03 9/12/91";
- X#endif
- X
- X#include <string.h>
- X#include <stdio.h>
- X#include <grp.h>
- X#include "config.h"
- X
- X#ifdef NDBM
- X#include <ndbm.h>
- XDBM *gr_dbm;
- X
- X#define GRP_FRAG 256
- X
- X/*
- X * gr_dbm_update
- X *
- X * Updates the DBM password files, if they exist.
- X */
- X
- Xint
- Xgr_dbm_update (gr)
- Xstruct group *gr;
- X{
- X datum key;
- X datum content;
- X char data[BUFSIZ*8];
- X char grpkey[60];
- X char *cp;
- X int len;
- X int i;
- X int cnt;
- X static int once;
- X
- X if (! once) {
- X if (! gr_dbm)
- X setgrent ();
- X
- X once++;
- X }
- X if (! gr_dbm)
- X return 0;
- X
- X len = gr_pack (gr, data);
- X
- X if (len <= GRP_FRAG) {
- X content.dsize = len;
- X content.dptr = data;
- X
- X key.dsize = strlen (gr->gr_name);
- X key.dptr = gr->gr_name;
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X
- X key.dsize = sizeof gr->gr_gid;
- X key.dptr = (char *) &gr->gr_gid;
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X
- X } else {
- X content.dsize = sizeof cnt;
- X content.dptr = (char *) &cnt;
- X cnt = (len + (GRP_FRAG-1)) / GRP_FRAG;
- X
- X key.dsize = strlen (gr->gr_name);
- X key.dptr = gr->gr_name;
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X
- X key.dsize = sizeof gr->gr_gid;
- X key.dptr = (char *) &gr->gr_gid;
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X
- X for (cp = data, i = 0;i < cnt;i++) {
- X content.dsize = len > GRP_FRAG ? GRP_FRAG:len;
- X len -= content.dsize;
- X content.dptr = cp;
- X cp += content.dsize;
- X
- X key.dsize = sizeof i + strlen (gr->gr_name);
- X key.dptr = grpkey;
- X memcpy (grpkey, (char *) &i, sizeof i);
- X strcpy (grpkey + sizeof i, gr->gr_name);
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X
- X key.dsize = sizeof i + sizeof gr->gr_gid;
- X key.dptr = grpkey;
- X memcpy (grpkey, (char *) &i, sizeof i);
- X memcpy (grpkey + sizeof i, (char *) &gr->gr_gid,
- X sizeof gr->gr_gid);
- X if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
- X return 0;
- X }
- X }
- X return 1;
- X}
- X
- X/*
- X * gr_dbm_remove
- X *
- X * Deletes the DBM group file entries, if they exist.
- X */
- X
- Xint
- Xgr_dbm_remove (gr)
- Xstruct group *gr;
- X{
- X datum key;
- X datum content;
- X char grpkey[60];
- X int i;
- X int cnt;
- X int errors = 0;
- X static int once;
- X
- X if (! once) {
- X if (! gr_dbm)
- X setgrent ();
- X
- X once++;
- X }
- X if (! gr_dbm)
- X return 0;
- X
- X key.dsize = strlen (gr->gr_name);
- X key.dptr = (char *) gr->gr_name;
- X content = dbm_fetch (gr_dbm, key);
- X if (content.dptr == 0)
- X ++errors;
- X else {
- X if (content.dsize == sizeof (int)) {
- X memcpy ((char *) &cnt, content.dptr, sizeof cnt);
- X
- X for (i = 0;i < cnt;i++) {
- X key.dsize = sizeof i + strlen (gr->gr_name);
- X key.dptr = grpkey;
- X memcpy (grpkey, (char *) &i, sizeof i);
- X strcpy (grpkey + sizeof i, gr->gr_name);
- X if (dbm_delete (gr_dbm, key))
- X ++errors;
- X }
- X } else {
- X if (dbm_delete (gr_dbm, key))
- X ++errors;
- X }
- X }
- X key.dsize = sizeof gr->gr_gid;
- X key.dptr = (char *) &gr->gr_gid;
- X content = dbm_fetch (gr_dbm, key);
- X if (content.dptr == 0)
- X ++errors;
- X else {
- X if (content.dsize == sizeof (int)) {
- X memcpy ((char *) &cnt, content.dptr, sizeof cnt);
- X
- X for (i = 0;i < cnt;i++) {
- X key.dsize = sizeof i + sizeof gr->gr_gid;
- X key.dptr = grpkey;
- X memcpy (grpkey, (char *) &i, sizeof i);
- X memcpy (grpkey + sizeof i, (char *) &gr->gr_gid,
- X sizeof gr->gr_gid);
- X
- X if (dbm_delete (gr_dbm, key))
- X ++errors;
- X }
- X } else {
- X if (dbm_delete (gr_dbm, key))
- X ++errors;
- X }
- X }
- X return errors ? 0:1;
- X}
- X#endif
- END_OF_FILE
- if test 3618 -ne `wc -c <'grdbm.c'`; then
- echo shar: \"'grdbm.c'\" unpacked with wrong size!
- fi
- # end of 'grdbm.c'
- fi
- if test -f 'groupmod.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'groupmod.c'\"
- else
- echo shar: Extracting \"'groupmod.c'\" \(8138 characters\)
- sed "s/^X//" >'groupmod.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)groupmod.c 3.3 08:43:51 9/12/91";
- X#endif
- X
- X#include <sys/types.h>
- X#include <stdio.h>
- X#include <grp.h>
- X#include <ctype.h>
- X#include <fcntl.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#include "config.h"
- X#include "shadow.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X#endif
- X
- Xchar group_name[BUFSIZ];
- Xchar group_newname[BUFSIZ];
- Xint group_id;
- Xint group_newid;
- X
- Xchar *Prog;
- X
- Xint oflg; /* permit non-unique group ID to be specified with -g */
- Xint gflg; /* new ID value for the group */
- Xint nflg; /* a new name has been specified for the group */
- X
- X#ifdef NDBM
- Xextern int gr_dbm_mode;
- Xextern int sg_dbm_mode;
- X#endif
- Xextern char *malloc();
- X
- Xextern struct group *getgrnam();
- Xextern struct group *gr_next();
- Xextern struct group *gr_locate();
- Xextern int gr_lock();
- Xextern int gr_unlock();
- Xextern int gr_rewind();
- Xextern int gr_open();
- X
- X#ifdef SHADOWGRP
- Xextern struct sgrp *sgr_locate();
- Xextern int sgr_lock();
- Xextern int sgr_unlock();
- Xextern int sgr_open();
- X#endif
- X
- X/*
- X * usage - display usage message and exit
- X */
- X
- Xusage ()
- X{
- X fprintf (stderr, "usage: groupmod [-g gid [-o]] [-n name] group\n");
- X exit (2);
- X}
- X
- X/*
- X * new_grent - updates the values in a group file entry
- X *
- X * new_grent() takes all of the values that have been entered and
- X * fills in a (struct group) with them.
- X */
- X
- Xvoid
- Xnew_grent (grent)
- Xstruct group *grent;
- X{
- X if (nflg)
- X grent->gr_name = strdup (group_newname);
- X
- X if (gflg)
- X grent->gr_gid = group_newid;
- X}
- X
- X#ifdef SHADOWGRP
- X/*
- X * new_sgent - updates the values in a shadow group file entry
- X *
- X * new_sgent() takes all of the values that have been entered and
- X * fills in a (struct sgrp) with them.
- X */
- X
- Xvoid
- Xnew_sgent (sgent)
- Xstruct sgrp *sgent;
- X{
- X if (nflg)
- X sgent->sg_name = strdup (group_newname);
- X}
- X#endif /* SHADOWGRP */
- X
- X/*
- X * grp_update - update group file entries
- X *
- X * grp_update() writes the new records to the group files.
- X */
- X
- Xvoid
- Xgrp_update ()
- X{
- X struct group grp;
- X struct group *ogrp;
- X#ifdef SHADOWGRP
- X struct sgrp sgrp;
- X#endif /* SHADOWGRP */
- X
- X /*
- X * Create the initial entries for this new group.
- X */
- X
- X grp = *(gr_locate (group_name));
- X new_grent (&grp);
- X#ifdef SHADOWGRP
- X sgrp = *(sgr_locate (group_name));
- X new_sgent (&sgrp);
- X#endif /* SHADOWGRP */
- X
- X /*
- X * Write out the new group file entry.
- X */
- X
- X if (! gr_update (&grp)) {
- X fprintf (stderr, "%s: error adding new group entry\n", Prog);
- X exit (1);
- X }
- X if (nflg && ! gr_remove (group_name)) {
- X fprintf (stderr, "%s: error removing group entry\n", Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (access ("/etc/group.pag", 0) == 0) {
- X if (! gr_dbm_update (&grp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n",
- X Prog);
- X exit (1);
- X }
- X if (nflg && (ogrp = getgrnam (group_name)) &&
- X ! gr_dbm_remove (ogrp)) {
- X fprintf (stderr, "%s: error removing group dbm entry\n",
- X Prog);
- X exit (1);
- X }
- X endgrent ();
- X }
- X#endif /* NDBM */
- X
- X#ifdef SHADOWGRP
- X
- X /*
- X * Write out the new shadow group entries as well.
- X */
- X
- X if (! sgr_update (&sgrp)) {
- X fprintf (stderr, "%s: error adding new group entry\n", Prog);
- X exit (1);
- X }
- X if (nflg && ! sgr_remove (group_name)) {
- X fprintf (stderr, "%s: error removing group entry\n", Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X
- X /*
- X * Update the DBM shadow group file with the new entry as well.
- X */
- X
- X if (access ("/etc/gshadow.pag", 0) == 0) {
- X if (! sgr_dbm_update (&sgrp)) {
- X fprintf (stderr,
- X "%s: cannot add new dbm shadow group entry\n",
- X Prog);
- X exit (1);
- X }
- X if (nflg && ! sgr_dbm_remove (group_name)) {
- X fprintf (stderr,
- X "%s: error removing shadow group dbm entry\n",
- X Prog);
- X exit (1);
- X }
- X endsgent ();
- X }
- X#endif /* NDBM */
- X#endif /* SHADOWGRP */
- X#ifdef USE_SYSLOG
- X if (nflg)
- X syslog (LOG_INFO, "change group `%s' to `%s'\n",
- X group_name, group_newname);
- X
- X if (gflg)
- X syslog (LOG_INFO, "change gid for `%s' to %d\n",
- X nflg ? group_name:group_newname, group_newid);
- X#endif /* USE_SYSLOG */
- X}
- X
- X/*
- X * check_new_gid - check the new GID value for uniqueness
- X *
- X * check_new_gid() insures that the new GID value is unique.
- X */
- X
- Xint
- Xcheck_new_gid ()
- X{
- X /*
- X * First, the easy stuff. If the ID can be duplicated, or if
- X * the ID didn't really change, just return. If the ID didn't
- X * change, turn off those flags. No sense doing needless work.
- X */
- X
- X if (oflg)
- X return 0;
- X
- X if (group_id == group_newid) {
- X gflg = 0;
- X return 0;
- X }
- X if (getgrgid (group_newid))
- X return -1;
- X
- X return 0;
- X}
- X
- X/*
- X * process_flags - perform command line argument setting
- X *
- X * process_flags() interprets the command line arguments and sets
- X * the values that the user will be created with accordingly. The
- X * values are checked for sanity.
- X */
- X
- Xvoid
- Xprocess_flags (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int optind;
- X extern char *optarg;
- X char *end;
- X int arg;
- X
- X while ((arg = getopt (argc, argv, "og:n:")) != EOF) {
- X switch (arg) {
- X case 'g':
- X gflg++;
- X group_newid = strtol (optarg, &end, 10);
- X if (*end != '\0') {
- X fprintf (stderr, "%s: invalid group %s\n",
- X Prog, optarg);
- X exit (3);
- X }
- X break;
- X case 'n':
- X if (strcmp (group_name, optarg)) {
- X nflg++;
- X strncpy (group_newname, optarg, BUFSIZ);
- X }
- X break;
- X case 'o':
- X if (! gflg)
- X usage ();
- X
- X oflg++;
- X break;
- X default:
- X usage ();
- X }
- X }
- X if (optind == argc - 1)
- X strcpy (group_name, argv[argc - 1]);
- X else
- X usage ();
- X}
- X
- X/*
- X * close_files - close all of the files that were opened
- X *
- X * close_files() closes all of the files that were opened for this
- X * new group. This causes any modified entries to be written out.
- X */
- X
- Xclose_files ()
- X{
- X if (! gr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
- X exit (1);
- X }
- X (void) gr_unlock ();
- X#ifdef SHADOWGRP
- X if (! sgr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X (void) sgr_unlock ();
- X#endif /* SHADOWGRP */
- X}
- X
- X/*
- X * open_files - lock and open the group files
- X *
- X * open_files() opens the two group files.
- X */
- X
- Xopen_files ()
- X{
- X if (! gr_lock ()) {
- X fprintf (stderr, "%s: unable to lock group file\n", Prog);
- X exit (1);
- X }
- X if (! gr_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open group file\n", Prog);
- X exit (1);
- X }
- X#ifdef SHADOWGRP
- X if (! sgr_lock ()) {
- X fprintf (stderr, "%s: unable to lock shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X if (! sgr_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open shadow group file\n",
- X Prog);
- X exit (1);
- X }
- X#endif /* SHADOWGRP */
- X}
- X
- X/*
- X * main - groupmod command
- X *
- X * The syntax of the groupmod command is
- X *
- X * groupmod [ -g gid [ -o ]] [ -n name ] group
- X *
- X * The flags are
- X * -g - specify a new group ID value
- X * -o - permit the group ID value to be non-unique
- X * -n - specify a new group name
- X */
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X
- X /*
- X * Get my name so that I can use it to report errors.
- X */
- X
- X if (Prog = strrchr (argv[0], '/'))
- X Prog++;
- X else
- X Prog = argv[0];
- X
- X#ifdef USE_SYSLOG
- X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- X#endif /* USE_SYSLOG */
- X
- X /*
- X * The open routines for the DBM files don't use read-write
- X * as the mode, so we have to clue them in.
- X */
- X
- X#ifdef NDBM
- X gr_dbm_mode = O_RDWR;
- X#ifdef SHADOWGRP
- X sg_dbm_mode = O_RDWR;
- X#endif /* SHADOWGRP */
- X#endif /* NDBM */
- X process_flags (argc, argv);
- X
- X /*
- X * Start with a quick check to see if the group exists.
- X */
- X
- X if (! getgrnam (group_name)) {
- X fprintf (stderr, "%s: group %s does not exist\n",
- X Prog, group_name);
- X exit (9);
- X }
- X
- X /*
- X * Do the hard stuff - open the files, create the group entries,
- X * then close and update the files.
- X */
- X
- X open_files ();
- X
- X grp_update ();
- X
- X close_files ();
- X exit (0);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 8138 -ne `wc -c <'groupmod.c'`; then
- echo shar: \"'groupmod.c'\" unpacked with wrong size!
- fi
- # end of 'groupmod.c'
- fi
- if test -f 'mkpasswd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mkpasswd.c'\"
- else
- echo shar: Extracting \"'mkpasswd.c'\" \(8625 characters\)
- sed "s/^X//" >'mkpasswd.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)mkpasswd.c 3.9 07:44:14 9/17/91";
- Xstatic char copyright[] = "Copyright 1990, 1991, John F. Haugh II";
- X#endif
- X
- X#include "config.h"
- X#include <stdio.h>
- X
- X#if !defined(DBM) && !defined(NDBM) /*{*/
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X fprintf(stderr, "%s: no DBM database on system - no action performed\n",
- X argv[0]);
- X exit(0);
- X}
- X
- X#else /*} defined(DBM) || defined(NDBM) {*/
- X
- X#include <fcntl.h>
- X#include "pwd.h"
- X#ifdef BSD
- X#include <strings.h>
- X#define strchr index
- X#define strrchr rindex
- X#else
- X#include <string.h>
- X#endif
- X
- X#ifdef DBM
- X#include <dbm.h>
- X#endif
- X#ifdef NDBM
- X#include <ndbm.h>
- X#include <grp.h>
- X#include "shadow.h"
- X
- XDBM *pw_dbm;
- XDBM *gr_dbm;
- XDBM *sp_dbm;
- XDBM *sgr_dbm;
- Xchar *fgetsx();
- X#endif
- X
- Xchar *CANT_OPEN = "%s: cannot open file %s\n";
- Xchar *CANT_OVERWRITE = "%s: cannot overwrite file %s\n";
- X#ifdef DBM
- Xchar *CANT_CREATE = "%s: cannot create %s\n";
- X#endif
- Xchar *DBM_OPEN_ERR = "%s: cannot open DBM files for %s\n";
- Xchar *PARSE_ERR = "%s: error parsing line\n\"%s\"\n";
- Xchar *LINE_TOO_LONG = "%s: the beginning with \"%.16s ...\" is too long\n";
- Xchar *ADD_REC = "adding record for name \"%s\"\n";
- Xchar *ADD_REC_ERR = "%s: error adding record for \"%s\"\n";
- Xchar *INFO = "added %d entries, longest was %d\n";
- X#ifdef NDBM
- Xchar *USAGE = "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n";
- X#else
- Xchar *USAGE = "Usage: %s [ -vf ] file\n";
- X#endif
- X
- Xchar *Progname;
- Xint vflg = 0;
- Xint fflg = 0;
- X#ifdef NDBM
- Xint gflg = 0;
- Xint sflg = 0;
- Xint pflg = 0;
- X#endif
- X
- Xvoid usage();
- X
- Xextern char *malloc();
- Xextern struct passwd *sgetpwent();
- Xextern int pw_dbm_update();
- X#ifdef NDBM
- Xextern struct group *sgetgrent();
- Xextern struct spwd *sgetspent();
- Xextern struct sgrp *sgetsgent();
- Xextern int sp_dbm_update();
- Xextern int gr_dbm_update();
- Xextern int sgr_dbm_update();
- X#endif
- X
- X/*
- X * mkpasswd - create DBM files for /etc/passwd-like input file
- X *
- X * mkpasswd takes an an argument the name of a file in /etc/passwd format
- X * and creates a DBM file keyed by user ID and name. The output files have
- X * the same name as the input file, with .dir and .pag appended.
- X *
- X * if NDBM is defined this command will also create look-aside files for
- X * /etc/group, /etc/shadow, and /etc/gshadow.
- X */
- X
- Xint
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int optind;
- X extern char *optarg;
- X FILE *fp; /* File pointer for input file */
- X char *file; /* Name of input file */
- X char *dir; /* Name of .dir file */
- X char *pag; /* Name of .pag file */
- X char *cp; /* Temporary character pointer */
- X int flag; /* Flag for command line option */
- X#ifdef DBM
- X int fd; /* File descriptor of open DBM file */
- X#endif
- X int cnt = 0; /* Number of entries in database */
- X int longest = 0; /* Longest entry in database */
- X int len; /* Length of input line */
- X int errors = 0; /* Count of errors processing file */
- X char buf[BUFSIZ*8]; /* Input line from file */
- X struct passwd *passwd; /* Pointer to password file entry */
- X#ifdef NDBM
- X struct group *group; /* Pointer to group file entry */
- X struct spwd *shadow; /* Pointer to shadow passwd entry */
- X struct sgrp *gshadow; /* Pointer to shadow group entry */
- X DBM *dbm; /* Pointer to new NDBM files */
- X DBM *dbm_open(); /* Function to open NDBM files */
- X#endif
- X
- X /*
- X * Figure out what my name is. I will use this later ...
- X */
- X
- X if (Progname = strrchr (argv[0], '/'))
- X Progname++;
- X else
- X Progname = argv[0];
- X
- X /*
- X * Figure out what the flags might be ...
- X */
- X
- X#ifdef NDBM
- X while ((flag = getopt (argc, argv, "fvpgs")) != EOF)
- X#else
- X while ((flag = getopt (argc, argv, "fv")) != EOF)
- X#endif
- X {
- X switch (flag) {
- X case 'v':
- X vflg++;
- X break;
- X case 'f':
- X fflg++;
- X break;
- X#ifdef NDBM
- X case 'g':
- X gflg++;
- X if (pflg)
- X usage ();
- X
- X break;
- X case 's':
- X sflg++;
- X break;
- X case 'p':
- X pflg++;
- X if (gflg)
- X usage ();
- X
- X break;
- X#endif
- X default:
- X usage ();
- X }
- X }
- X
- X#ifdef NDBM
- X /*
- X * Backwards compatibility fix for -p flag ...
- X */
- X
- X if (! sflg && ! gflg)
- X pflg++;
- X#endif
- X
- X /*
- X * The last and only remaining argument must be the file name
- X */
- X
- X if (argc - 1 != optind)
- X usage ();
- X
- X file = argv[optind];
- X
- X if (! (fp = fopen (file, "r"))) {
- X fprintf (stderr, CANT_OPEN, Progname, file);
- X exit (1);
- X }
- X
- X /*
- X * Make the filenames for the two DBM files.
- X */
- X
- X dir = malloc (strlen (file) + 5); /* space for .dir file */
- X strcat (strcpy (dir, file), ".dir");
- X
- X pag = malloc (strlen (file) + 5); /* space for .pag file */
- X strcat (strcpy (pag, file), ".pag");
- X
- X /*
- X * Remove existing files if requested.
- X */
- X
- X if (fflg) {
- X (void) unlink (dir);
- X (void) unlink (pag);
- X }
- X
- X /*
- X * Create the two DBM files - it is an error for these files
- X * to have existed already.
- X */
- X
- X if (access (dir, 0) == 0) {
- X fprintf (stderr, CANT_OVERWRITE, Progname, dir);
- X exit (1);
- X }
- X if (access (pag, 0) == 0) {
- X fprintf (stderr, CANT_OVERWRITE, Progname, pag);
- X exit (1);
- X }
- X
- X#ifdef NDBM
- X if (sflg)
- X umask (077);
- X else
- X#endif
- X umask (0);
- X#ifdef DBM
- X if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
- X fprintf (stderr, CANT_CREATE, Progname, dir);
- X exit (1);
- X } else
- X close (fd);
- X
- X if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
- X fprintf (stderr, CANT_CREATE, Progname, pag);
- X unlink (dir);
- X exit (1);
- X } else
- X close (fd);
- X#endif
- X
- X /*
- X * Now the DBM database gets initialized
- X */
- X
- X#ifdef DBM
- X if (dbminit (file) == -1) {
- X fprintf (stderr, DBM_OPEN_ERR, Progname, file);
- X exit (1);
- X }
- X#endif
- X#ifdef NDBM
- X if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
- X fprintf (stderr, DBM_OPEN_ERR, Progname, file);
- X exit (1);
- X }
- X if (gflg) {
- X if (sflg)
- X sgr_dbm = dbm;
- X else
- X gr_dbm = dbm;
- X } else {
- X if (sflg)
- X sp_dbm = dbm;
- X else
- X pw_dbm = dbm;
- X }
- X#endif
- X
- X /*
- X * Read every line in the password file and convert it into a
- X * data structure to be put in the DBM database files.
- X */
- X
- X#ifdef NDBM
- X while (fgetsx (buf, BUFSIZ, fp) != NULL)
- X#else
- X while (fgets (buf, BUFSIZ, fp) != NULL)
- X#endif
- X {
- X
- X /*
- X * Get the next line and strip off the trailing newline
- X * character.
- X */
- X
- X buf[sizeof buf - 1] = '\0';
- X if (! (cp = strchr (buf, '\n'))) {
- X fprintf (stderr, LINE_TOO_LONG, Progname, buf);
- X exit (1);
- X }
- X *cp = '\0';
- X len = strlen (buf);
- X
- X /*
- X * Parse the password file line into a (struct passwd).
- X * Erroneous lines cause error messages, but that's
- X * all. YP lines are ignored completely.
- X */
- X
- X if (buf[0] == '-' || buf[0] == '+')
- X continue;
- X
- X#ifdef DBM
- X if (! (passwd = sgetpwent (buf)))
- X#endif
- X#ifdef NDBM
- X if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
- X || ((sflg && pflg) && (shadow = sgetspent (buf)))
- X || ((! sflg && gflg) && (group = sgetgrent (buf)))
- X || ((sflg && gflg) && (gshadow = sgetsgent (buf)))))
- X#endif
- X {
- X fprintf (stderr, PARSE_ERR, Progname, buf);
- X errors++;
- X continue;
- X }
- X#ifdef DBM
- X if (vflg)
- X printf (ADD_REC, passwd->pw_name);
- X
- X if (! pw_dbm_update (passwd))
- X fprintf (stderr, ADD_REC_ERR,
- X Progname, passwd->pw_name);
- X#endif
- X#ifdef NDBM
- X if (vflg) {
- X if (!sflg && pflg) printf (ADD_REC, passwd->pw_name);
- X if (sflg && pflg) printf (ADD_REC, shadow->sp_namp);
- X if (!sflg && gflg) printf (ADD_REC, group->gr_name);
- X if (sflg && gflg) printf (ADD_REC, gshadow->sg_name);
- X }
- X if (! sflg && pflg && ! pw_dbm_update (passwd))
- X fprintf (stderr, ADD_REC_ERR,
- X Progname, passwd->pw_name);
- X
- X if (sflg && pflg && ! sp_dbm_update (shadow))
- X fprintf (stderr, ADD_REC_ERR,
- X Progname, shadow->sp_namp);
- X
- X if (! sflg && gflg && ! gr_dbm_update (group))
- X fprintf (stderr, ADD_REC_ERR,
- X Progname, group->gr_name);
- X
- X if (sflg && gflg && ! sgr_dbm_update (gshadow))
- X fprintf (stderr, ADD_REC_ERR,
- X Progname, gshadow->sg_name);
- X#endif
- X
- X /*
- X * Update the longest record and record count
- X */
- X
- X if (len > longest)
- X longest = len;
- X cnt++;
- X }
- X
- X /*
- X * Tell the user how things went ...
- X */
- X
- X if (vflg)
- X printf (INFO, cnt, longest);
- X
- X exit (errors);
- X /*NOTREACHED*/
- X}
- X
- X/*
- X * usage - print error message and exit
- X */
- X
- Xvoid
- Xusage ()
- X{
- X fprintf (stderr, USAGE, Progname);
- X exit (1);
- X /*NOTREACHED*/
- X}
- X#endif /*} defined(DBM) || defined(NDBM) */
- END_OF_FILE
- if test 8625 -ne `wc -c <'mkpasswd.c'`; then
- echo shar: \"'mkpasswd.c'\" unpacked with wrong size!
- fi
- # end of 'mkpasswd.c'
- fi
- if test -f 'port.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'port.c'\"
- else
- echo shar: Extracting \"'port.c'\" \(8978 characters\)
- sed "s/^X//" >'port.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1989, 1990, 1991, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include <stdio.h>
- X#include <time.h>
- X#include <sys/types.h>
- X#include <ctype.h>
- X#include <errno.h>
- X#ifndef BSD
- X#include <string.h>
- X#else
- X#include <strings.h>
- X#define strchr index
- X#define strrchr rindex
- X#endif
- X#include "port.h"
- X
- X#ifndef lint
- Xstatic char _sccsid[] = "@(#)port.c 3.1 08:59:32 2/8/91";
- X#endif
- X
- Xextern int errno;
- X
- Xstatic FILE *ports;
- X
- X/*
- X * setttyent - open /etc/porttime file or rewind
- X *
- X * the /etc/porttime file is rewound if already open, or
- X * opened for reading.
- X */
- X
- Xvoid
- Xsetttyent ()
- X{
- X if (ports)
- X rewind (ports);
- X else
- X ports = fopen (PORTS, "r");
- X}
- X
- X/*
- X * endttyent - close the /etc/porttime file
- X *
- X * the /etc/porttime file is closed and the ports variable set
- X * to NULL to indicate that the /etc/porttime file is no longer
- X * open.
- X */
- X
- Xvoid
- Xendttyent ()
- X{
- X if (ports)
- X fclose (ports);
- X
- X ports = (FILE *) 0;
- X}
- X
- X/*
- X * getttyent - read a single entry from /etc/porttime
- X *
- X * the next line in /etc/porttime is converted to a (struct port)
- X * and a pointer to a static (struct port) is returned to the
- X * invoker. NULL is returned on either EOF or error. errno is
- X * set to EINVAL on error to distinguish the two conditions.
- X */
- X
- Xstruct port *
- Xgetttyent ()
- X{
- X static struct port port; /* static struct to point to */
- X static char buf[BUFSIZ]; /* some space for stuff */
- X static char *ttys[PORT_TTY+1]; /* some pointers to tty names */
- X static char *users[PORT_IDS+1]; /* some pointers to user ids */
- X static struct pt_time times[PORT_TIMES+1]; /* time ranges */
- X char *cp; /* pointer into line */
- X int time; /* scratch time of day */
- X int i, j;
- X int saveerr = errno; /* errno value on entry */
- X
- X /*
- X * If the ports file is not open, open the file. Do not rewind
- X * since we want to search from the beginning each time.
- X */
- X
- X if (! ports)
- X setttyent ();
- X
- X if (! ports) {
- X errno = saveerr;
- X return 0;
- X }
- X
- X /*
- X * Common point for beginning a new line -
- X *
- X * - read a line, and NUL terminate
- X * - skip lines which begin with '#'
- X * - parse off the tty names
- X * - parse off a list of user names
- X * - parse off a list of days and times
- X */
- X
- Xagain:
- X
- X /*
- X * Get the next line and remove the last character, which
- X * is a '\n'. Lines which begin with '#' are all ignored.
- X */
- X
- X if (fgets (buf, BUFSIZ, ports) == 0) {
- X errno = saveerr;
- X return 0;
- X }
- X if (buf[0] == '#')
- X goto again;
- X
- X /*
- X * Get the name of the TTY device. It is the first colon
- X * separated field, and is the name of the TTY with no
- X * leading "/dev". The entry '*' is used to specify all
- X * TTY devices.
- X */
- X
- X buf[strlen (buf) - 1] = 0;
- X
- X port.pt_names = ttys;
- X for (cp = buf, j = 0;j < PORT_TTY;j++) {
- X port.pt_names[j] = cp;
- X while (*cp && *cp != ':' && *cp != ',')
- X cp++;
- X
- X if (! *cp)
- X goto again; /* line format error */
- X
- X if (*cp == ':') /* end of tty name list */
- X break;
- X
- X if (*cp == ',') /* end of current tty name */
- X *cp++ = '\0';
- X }
- X *cp++ = 0;
- X port.pt_names[j + 1] = (char *) 0;
- X
- X /*
- X * Get the list of user names. It is the second colon
- X * separated field, and is a comma separated list of user
- X * names. The entry '*' is used to specify all usernames.
- X * The last entry in the list is a (char *) 0 pointer.
- X */
- X
- X if (*cp != ':') {
- X port.pt_users = users;
- X port.pt_users[0] = cp;
- X
- X for (j = 1;*cp != ':';cp++) {
- X if (*cp == ',' && j < PORT_IDS) {
- X *cp++ = 0;
- X port.pt_users[j++] = cp;
- X }
- X }
- X port.pt_users[j] = 0;
- X } else
- X port.pt_users = 0;
- X
- X if (*cp != ':')
- X goto again;
- X
- X *cp++ = 0;
- X
- X /*
- X * Get the list of valid times. The times field is the third
- X * colon separated field and is a list of days of the week and
- X * times during which this port may be used by this user. The
- X * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
- X *
- X * In addition, the value 'Al' represents all 7 days, and 'Wk'
- X * represents the 5 weekdays.
- X *
- X * Times are given as HHMM-HHMM. The ending time may be before
- X * the starting time. Days are presumed to wrap at 0000.
- X */
- X
- X if (*cp == '\0') {
- X port.pt_times = 0;
- X return &port;
- X }
- X
- X port.pt_times = times;
- X
- X /*
- X * Get the next comma separated entry
- X */
- X
- X for (j = 0;*cp && j < PORT_TIMES;j++) {
- X
- X /*
- X * Start off with no days of the week
- X */
- X
- X port.pt_times[j].t_days = 0;
- X
- X /*
- X * Check each two letter sequence to see if it is
- X * one of the abbreviations for the days of the
- X * week or the other two values.
- X */
- X
- X for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
- X switch ((cp[i] << 8) | (cp[i + 1])) {
- X case ('S' << 8) | 'u':
- X port.pt_times[j].t_days |= 01;
- X break;
- X case ('M' << 8) | 'o':
- X port.pt_times[j].t_days |= 02;
- X break;
- X case ('T' << 8) | 'u':
- X port.pt_times[j].t_days |= 04;
- X break;
- X case ('W' << 8) | 'e':
- X port.pt_times[j].t_days |= 010;
- X break;
- X case ('T' << 8) | 'h':
- X port.pt_times[j].t_days |= 020;
- X break;
- X case ('F' << 8) | 'r':
- X port.pt_times[j].t_days |= 040;
- X break;
- X case ('S' << 8) | 'a':
- X port.pt_times[j].t_days |= 0100;
- X break;
- X case ('W' << 8) | 'k':
- X port.pt_times[j].t_days |= 076;
- X break;
- X case ('A' << 8) | 'l':
- X port.pt_times[j].t_days |= 0177;
- X break;
- X default:
- X errno = EINVAL;
- X return 0;
- X }
- X }
- X
- X /*
- X * The default is 'Al' if no days were seen.
- X */
- X
- X if (i == 0)
- X port.pt_times[j].t_days = 0177;
- X
- X /*
- X * The start and end times are separated from each
- X * other by a '-'. The times are four digit numbers
- X * representing the times of day.
- X */
- X
- X for (time = 0;cp[i] && isdigit (cp[i]);i++)
- X time = time * 10 + cp[i] - '0';
- X
- X if (cp[i] != '-' || time > 2400 || time % 100 > 59)
- X goto again;
- X port.pt_times[j].t_start = time;
- X cp = cp + i + 1;
- X
- X for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
- X time = time * 10 + cp[i] - '0';
- X
- X if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
- X goto again;
- X
- X port.pt_times[j].t_end = time;
- X cp = cp + i + 1;
- X }
- X
- X /*
- X * The end of the list is indicated by a pair of -1's for the
- X * start and end times.
- X */
- X
- X port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
- X
- X return &port;
- X}
- X
- X/*
- X * getttyuser - get ports information for user and tty
- X *
- X * getttyuser() searches the ports file for an entry with a TTY
- X * and user field both of which match the supplied TTY and
- X * user name. The file is searched from the beginning, so the
- X * entries are treated as an ordered list.
- X */
- X
- Xstruct port *
- Xgetttyuser (tty, user)
- Xchar *tty;
- Xchar *user;
- X{
- X int i, j;
- X struct port *port;
- X
- X setttyent ();
- X
- X while (port = getttyent ()) {
- X if (port->pt_names == 0 || port->pt_users == 0)
- X continue;
- X
- X for (i = 0;port->pt_names[i];i++)
- X if (strcmp (port->pt_names[i], tty) == 0 ||
- X strcmp (port->pt_names[i], "*") == 0)
- X break;
- X
- X if (port->pt_names[i] == 0)
- X continue;
- X
- X for (j = 0;port->pt_users[j];j++)
- X if (strcmp (user, port->pt_users[j]) == 0 ||
- X strcmp (port->pt_users[j], "*") == 0)
- X break;
- X
- X if (port->pt_users[j] != 0)
- X break;
- X }
- X endttyent ();
- X return port;
- X}
- X
- X/*
- X * isttytime - tell if a given user may login at a particular time
- X *
- X * isttytime searches the ports file for an entry which matches
- X * the user name and TTY given.
- X */
- X
- Xint
- Xisttytime (id, port, clock)
- Xchar *id;
- Xchar *port;
- Xlong clock;
- X{
- X int i;
- X int time;
- X struct port *pp;
- X struct tm *tm,
- X *localtime();
- X
- X /*
- X * Try to find a matching entry for this user. Default to
- X * letting the user in - there are pleny of ways to have an
- X * entry to match all users.
- X */
- X
- X if (! (pp = getttyuser (port, id)))
- X return 1;
- X
- X /*
- X * The entry is there, but has not time entries - don't
- X * ever let them login.
- X */
- X
- X if (pp->pt_times == 0)
- X return 0;
- X
- X /*
- X * The current time is converted to HHMM format for
- X * comparision against the time values in the TTY entry.
- X */
- X
- X tm = localtime (&clock);
- X time = tm->tm_hour * 100 + tm->tm_min;
- X
- X /*
- X * Each time entry is compared against the current
- X * time. For entries with the start after the end time,
- X * the comparision is made so that the time is between
- X * midnight and either the start or end time.
- X */
- X
- X for (i = 0;pp->pt_times[i].t_start != -1;i++) {
- X if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
- X continue;
- X
- X if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
- X if (time >= pp->pt_times[i].t_start &&
- X time <= pp->pt_times[i].t_end)
- X return 1;
- X } else {
- X if (time >= pp->pt_times[i].t_start ||
- X time <= pp->pt_times[i].t_end)
- X return 1;
- X }
- X }
- X
- X /*
- X * No matching time entry was found, user shouldn't
- X * be let in right now.
- X */
- X
- X return 0;
- X}
- END_OF_FILE
- if test 8978 -ne `wc -c <'port.c'`; then
- echo shar: \"'port.c'\" unpacked with wrong size!
- fi
- # end of 'port.c'
- fi
- if test -f 'shadow.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'shadow.c'\"
- else
- echo shar: Extracting \"'shadow.c'\" \(5851 characters\)
- sed "s/^X//" >'shadow.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1989, 1990, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X */
- X
- X#include "shadow.h"
- X#include "config.h"
- X#include <stdio.h>
- X
- X#ifndef BSD
- X#include <string.h>
- X#include <memory.h>
- X#else
- X#include <strings.h>
- X#define strchr index
- X#define strrchr rindex
- X#endif
- X
- X#ifdef NDBM
- X#include <ndbm.h>
- X#include <fcntl.h>
- XDBM *sp_dbm;
- Xint sp_dbm_mode = -1;
- Xstatic int dbmopened;
- Xstatic int dbmerror;
- X#endif
- X
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)shadow.c 3.9 08:44:32 9/12/91";
- X#endif
- X
- Xstatic FILE *shadow;
- Xstatic char spwbuf[BUFSIZ];
- Xstatic struct spwd spwd;
- X
- X#define FIELDS 9
- X#define OFIELDS 5
- X
- Xvoid
- Xsetspent ()
- X{
- X if (shadow)
- X rewind (shadow);
- X else
- X shadow = fopen (SHADOW, "r");
- X
- X /*
- X * Attempt to open the DBM files if they have never been opened
- X * and an error has never been returned.
- X */
- X
- X#ifdef NDBM
- X if (! dbmerror && ! dbmopened) {
- X int mode;
- X char dbmfiles[BUFSIZ];
- X
- X strcpy (dbmfiles, SHADOW);
- X strcat (dbmfiles, ".pag");
- X
- X if (sp_dbm_mode == -1)
- X mode = O_RDWR;
- X else
- X mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY;
- X
- X if (! (sp_dbm = dbm_open (SHADOW, mode, 0)))
- X dbmerror = 1;
- X else
- X dbmopened = 1;
- X }
- X#endif
- X}
- X
- Xvoid
- Xendspent ()
- X{
- X if (shadow)
- X (void) fclose (shadow);
- X
- X shadow = (FILE *) 0;
- X#ifdef NDBM
- X if (dbmopened && sp_dbm) {
- X dbm_close (sp_dbm);
- X sp_dbm = 0;
- X }
- X dbmopened = 0;
- X dbmerror = 0;
- X#endif
- X}
- X
- Xstruct spwd *
- Xsgetspent (string)
- Xchar *string;
- X{
- X char *fields[FIELDS];
- X char *cp;
- X char *cpp;
- X int atoi ();
- X long atol ();
- X int i;
- X
- X strncpy (spwbuf, string, BUFSIZ-1);
- X spwbuf[BUFSIZ-1] = '\0';
- X
- X if (cp = strrchr (spwbuf, '\n'))
- X *cp = '\0';
- X
- X for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) {
- X fields[i] = cp;
- X while (*cp && *cp != ':')
- X cp++;
- X
- X if (*cp)
- X *cp++ = '\0';
- X }
- X if (i == (FIELDS-1))
- X fields[i++] = cp;
- X
- X if (*cp || (i != FIELDS && i != OFIELDS))
- X return 0;
- X
- X spwd.sp_namp = fields[0];
- X spwd.sp_pwdp = fields[1];
- X
- X if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[2][0] == '\0')
- X spwd.sp_lstchg = -1;
- X
- X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[3][0] == '\0')
- X spwd.sp_min = -1;
- X
- X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[4][0] == '\0')
- X spwd.sp_max = -1;
- X
- X if (i == OFIELDS) {
- X spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
- X spwd.sp_flag = -1;
- X
- X return &spwd;
- X }
- X if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[5][0] == '\0')
- X spwd.sp_warn = -1;
- X
- X if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[6][0] == '\0')
- X spwd.sp_inact = -1;
- X
- X if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[7][0] == '\0')
- X spwd.sp_expire = -1;
- X
- X if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp)
- X return 0;
- X else if (fields[8][0] == '\0')
- X spwd.sp_flag = -1;
- X
- X return (&spwd);
- X}
- X
- Xstruct spwd
- X*fgetspent (fp)
- XFILE *fp;
- X{
- X char buf[BUFSIZ];
- X
- X if (! fp)
- X return (0);
- X
- X if (fgets (buf, BUFSIZ, fp) == (char *) 0)
- X return (0);
- X
- X return sgetspent (buf);
- X}
- X
- Xstruct spwd
- X*getspent ()
- X{
- X if (! shadow)
- X setspent ();
- X
- X return (fgetspent (shadow));
- X}
- X
- Xstruct spwd
- X*getspnam (name)
- Xchar *name;
- X{
- X struct spwd *sp;
- X#ifdef NDBM
- X datum key;
- X datum content;
- X#endif
- X
- X setspent ();
- X
- X#ifdef NDBM
- X
- X /*
- X * If the DBM file are now open, create a key for this UID and
- X * try to fetch the entry from the database. A matching record
- X * will be unpacked into a static structure and returned to
- X * the user.
- X */
- X
- X if (dbmopened) {
- X key.dsize = strlen (name);
- X key.dptr = name;
- X
- X content = dbm_fetch (sp_dbm, key);
- X if (content.dptr != 0) {
- X memcpy (spwbuf, content.dptr, content.dsize);
- X spw_unpack (spwbuf, content.dsize, &spwd);
- X return &spwd;
- X }
- X }
- X#endif
- X while ((sp = getspent ()) != (struct spwd *) 0) {
- X if (strcmp (name, sp->sp_namp) == 0)
- X return (sp);
- X }
- X return (0);
- X}
- X
- Xint
- Xputspent (sp, fp)
- Xstruct spwd *sp;
- XFILE *fp;
- X{
- X int errors = 0;
- X
- X if (! fp || ! sp)
- X return -1;
- X
- X if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0)
- X errors++;
- X
- X if (sp->sp_lstchg != -1) {
- X if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0)
- X errors++;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_min != -1) {
- X if (fprintf (fp, "%ld:", sp->sp_min) < 0)
- X errors++;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_max != -1) {
- X if (fprintf (fp, "%ld", sp->sp_max) < 0)
- X errors++;
- X }
- X
- X /*
- X * See if the structure has any of the SVR4 fields in
- X * it. If none of those fields have any data there is
- X * no reason to write them out since they will be filled
- X * in the same way when they are read back in. Otherwise
- X * there is at least one SVR4 field that must be output.
- X */
- X
- X if (sp->sp_warn == -1 && sp->sp_inact == -1 &&
- X sp->sp_expire == -1 && sp->sp_flag == -1) {
- X if (putc ('\n', fp) == EOF || errors)
- X return -1;
- X else
- X return 0;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_warn != -1) {
- X if (fprintf (fp, "%ld:", sp->sp_warn) < 0)
- X errors++;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_inact != -1) {
- X if (fprintf (fp, "%ld:", sp->sp_inact) < 0)
- X errors++;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_expire != -1) {
- X if (fprintf (fp, "%ld:", sp->sp_expire) < 0)
- X errors++;
- X } else if (putc (':', fp) == EOF)
- X errors++;
- X
- X if (sp->sp_flag != -1) {
- X if (fprintf (fp, "%ld", sp->sp_flag) < 0)
- X errors++;
- X }
- X if (putc ('\n', fp) == EOF)
- X errors++;
- X
- X if (errors)
- X return -1;
- X else
- X return 0;
- X}
- END_OF_FILE
- if test 5851 -ne `wc -c <'shadow.c'`; then
- echo shar: \"'shadow.c'\" unpacked with wrong size!
- fi
- # end of 'shadow.c'
- fi
- echo shar: End of archive 7 \(of 11\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-